# +----------------------------------------------------------------------
# | ChatWork智能聊天办公系统
# +----------------------------------------------------------------------
# | 软件声明: 本系统并非自由软件,未经授权任何形式的商业使用均属非法。
# | 版权保护: 任何企业和个人不允许对程序代码以任何形式任何目的复制/分发。
# | 授权要求: 如有商业使用需求,请务必先与版权所有者取得联系并获得正式授权。
# +----------------------------------------------------------------------
# | Author: ChatWork Team <2474369941@qq.com>
# +----------------------------------------------------------------------
import json
import time
from pydantic import TypeAdapter
from tortoise.queryset import Q
from hypertext import PagingResult
from common.utils.urls import UrlUtil
from common.enums.voice import VoiceEnum
from common.enums.agent import AgentEnum
from common.enums.models import ModelsEnum
from common.enums.notice import NoticeEnum
from common.models.users import UserModel
from common.models.dev import DevModelsModel
from common.models.agents import AgentKnowModel, AgentMcpModel
from common.models.agents import AgentRobotModel
from plugins.msg.driver import MsgDriver
from apps.admin.schemas.agent.robot import smarter_schema as schema
from apps.admin.schemas.agent.know.manage_schema import KnowWholeVo


class RobotSmarterService:

    @classmethod
    async def lists(cls, params: schema.RobotSearchIn) -> PagingResult[schema.RobotListVo]:
        """
        智能体列表。

        Args:
            params (schema.RobotSearchIn): 智能体查询参数。

        Returns:
            PagingResult[schema.RobotListVo]: 智能体分页列表Vo。

        Author:
            zero
        """
        # 查询条件
        where = AgentRobotModel.build_search({
            "%like%": ["name"],
            "=": ["is_disable"],
        }, params.__dict__)

        where.append(Q(is_delete=0))
        if params.user:
            condition = [Q(nickname__icontains=params.user) | Q(sn=params.user)]
            users = await UserModel.filter(*condition).filter(is_delete=0).limit(200).values("id")
            ids = [int(item["id"]) for item in users] or [0]
            where.append(Q(user_id__in=ids))

        # 查询数据
        _model = AgentRobotModel.filter(*where).order_by("-id")
        _pager = await AgentRobotModel.paginate(
            model=_model,
            page_no=params.page_no,
            page_size=params.page_size,
            fields=AgentRobotModel.without_field("is_delete,delete_time")
        )

        # 查询用户
        user_ids = [item["user_id"] for item in _pager.lists if item["user_id"]]
        users: dict = await UserModel.queryUserDictsById(user_ids)

        # 查询模型
        llm_list = [item["llm_models"] for item in _pager.lists if item["llm_models"]]
        models = await DevModelsModel.get_model_alias(llm_list, ModelsEnum.TYPE_CHAT)

        # 处理数据
        _lists = []
        for item in _pager.lists:
            user = users.get(item["user_id"], {})
            cModel = models.get(item["llm_models"], {})
            item["mcp_num"] = len(set([int(x) for x in item["mcp_ids"].split(",") if x]))
            item["know_num"] = len(set([int(x) for x in item["know_ids"].split(",") if x]))
            item["logo"] = await UrlUtil.to_absolute_url(item["logo"])
            item["model"] = cModel.get("name") + ":" + cModel["model"] if cModel else ""
            item["search_mode"] = AgentEnum.get_retrieve_desc(item["search_mode"])
            item["user"] = {
                "sn": user.get("sn", ""),
                "nickname": user.get("nickname", ""),
                "mobile": user.get("mobile", ""),
                "avatar": await UrlUtil.to_absolute_url(user.get("avatar", ""))
            }

            _lists.append(TypeAdapter(schema.RobotListVo).validate_python(item))

        _pager.lists = _lists
        return _pager

    @classmethod
    async def detail(cls, id_: int) -> schema.RobotDetailVo:
        """
        智能体详情。

        Args:
            id_ (int): 智能体ID。

        Returns:
            schema.RobotDetailVo: 智能体详情Vo。

        Author:
            zero
        """
        # 查找机器人
        robot = await AgentRobotModel.filter(id=id_, is_delete=0).get()

        # 关联知识库
        knows = []
        if robot.know_ids:
            models = []
            know_ids = robot.know_ids.split(",")
            _knows = await AgentKnowModel.filter(id__in=know_ids, is_delete=0).all()
            vector = [item.vector_model.split(":")[0] for item in _knows if item.vector_model]
            if vector:
                models = await (DevModelsModel
                                .filter(is_delete=0)
                                .filter(scene=ModelsEnum.TYPE_VECTOR)
                                .filter(mark__in=list(set(vector)))
                                .all().values_list("mark", "name"))
                models = {k: v for k, v in models}

            for item in _knows:
                mark = item.vector_model.split(":")[0]
                knows.append(KnowWholeVo(
                    code=item.code,
                    logo=await UrlUtil.to_absolute_url(item.logo),
                    name=item.name,
                    vector_name=models.get(mark) or "-",
                    vector_model=item.vector_model,
                    is_disable=item.is_disable
                ))

        # 关联MCP
        mcps = []
        if robot.mcp_ids:
            mcp_ids = robot.mcp_ids.split(",")
            _mcps = await AgentMcpModel.filter(id__in=mcp_ids, is_delete=0).all()
            for item in _mcps:
                mcps.append(schema.RobotMcpVo(
                    code=item.code,
                    logo=await UrlUtil.to_absolute_url(item.logo),
                    name=item.name,
                    is_disable=item.is_disable,
                ))

        # 模型的配置
        llm_name = ""
        llm_config = []
        if robot.llm_models:
            configs = json.loads(robot.llm_config)
            mark: str = robot.llm_models.split(":")[0]
            models = await DevModelsModel.filter(mark=mark, scene=ModelsEnum.TYPE_CHAT).first()
            if models:
                llm_name = models.name
                setting: dict = ModelsEnum.chat_models().get(models.channel)
                for conf in setting.get("configs")[0]["config"]:
                    conf["default"] = configs.get(conf["key"], "")
                    llm_config.append(conf)

        # 语音播报
        broad = json.loads(robot.broadcast or "{}")
        voice = broad.get("model", "").split(":")[0]
        speech = VoiceEnum.get_default_speech(voice) or {}
        broadcast = {
            "model": broad.get("model", str("")),
            "speed": broad.get("speed", 0.25),
            "speed_range": speech.get("speed_range", [0.25, 4.0, 0.1])
        }

        # 返回信息
        return schema.RobotDetailVo(
            code=robot.code,
            type=robot.type,
            logo=await UrlUtil.to_absolute_url(robot.logo),
            name=robot.name,
            intro=robot.intro,
            search_mode=robot.search_mode,
            search_tokens=robot.search_tokens,
            search_similar=robot.search_similar,
            ranking_status=robot.ranking_status,
            optimize_ask=robot.optimize_ask,
            prompt_roles=robot.prompt_roles or "",
            prompt_limit=robot.prompt_limit or "",
            welcome_text=robot.welcome_text or "",
            question_guide=robot.question_guide,
            max_upload_num=robot.max_upload_num,
            is_upload_files=robot.is_upload_files,
            is_upload_image=robot.is_upload_image,
            is_show_timed=robot.is_show_timed,
            is_show_quote=robot.is_show_quote,
            is_show_context=robot.is_show_context,
            is_original_reply=robot.is_original_reply,
            empty_search_text=robot.empty_search_text or "",
            empty_search_type=robot.empty_search_type or "",
            llm_name=llm_name,
            llm_models=robot.llm_models,
            llm_config=llm_config,
            knows=knows,
            mcps=mcps,
            broadcast=broadcast
        )

    @classmethod
    async def delete(cls, id_: int, reason: str):
        """
        智能体删除。

        Args:
            id_ (int): 智能体ID。
            reason (str): 原因信息。

        Author:
            zero
        """
        # 查找机器人
        robot = await AgentRobotModel.filter(id=id_, is_delete=0).get()

        # 删除机器人
        await AgentRobotModel.filter(id=id_, is_delete=0).update(
            is_delete=1,
            delete_time=int(time.time())
        )

        # 发送用户通知
        await MsgDriver.send(scene=NoticeEnum.ROBOT_DELETE, params={
            "user_id": robot.user_id,
            "code": robot.code,
            "name": robot.name,
            "reason": reason
        })

    @classmethod
    async def disable(cls, id_: int, reason: str):
        """
        智能体禁用。

        Args:
            id_ (int): 智能体ID。
            reason (str): 原因信息。

        Author:
            zero
        """
        # 查找机器人
        robot = await AgentRobotModel.filter(id=id_, is_delete=0).get()

        # 调整状态值
        status = 0 if robot.is_disable else 1
        await AgentRobotModel.filter(id=id_, is_delete=0).update(
            is_disable=status,
            update_time=int(time.time())
        )

        # 发送用户通知
        scene = NoticeEnum.ROBOT_RESTORE if status == 0 else NoticeEnum.ROBOT_DISABLE
        await MsgDriver.send(scene=scene, params={
            "user_id": robot.user_id,
            "code": robot.code,
            "name": robot.name,
            "reason": reason
        })
